"use server";
import {
  ForgotSchema,
  ForgotVerificationSchema,
  LoginSchema,
  RegisterSchema,
  RegisterVerificationSchema,
} from "@/schemas/auth";
import prisma from "@/lib/prisma";
import bcrypt from "bcryptjs";
import { signIn } from "@/lib/auth";
import { AuthError } from "next-auth";
import { getUserByEmail } from "@/data/user";
import {
  generateVerificationToken,
  getVerificationTokenByEmail,
  getVerificationTokenByToken,
} from "@/data/verification-token";
import { VerificationTokenType } from "@/lib/enums";
import type {
  ForgotFormData,
  ForgotVerificationFormData,
  LoginFormData,
  RegisterFormData,
} from "@/schemas/auth";
import { getTranslations } from "next-intl/server";
export const RegisterAction = async (values: RegisterFormData) => {
  const tZod = await getTranslations("zod");
  const validatedFields = RegisterSchema(tZod).safeParse(values);
  if (!validatedFields.success) return { error: "Invalid fields" };

  const user = await getUserByEmail(validatedFields.data.email);

  if (user) return { error: "User already exists" };

  const verificationToken = await generateVerificationToken({
    email: values.email,
    type: VerificationTokenType.RegisterToken,
  });
  if (verificationToken) {
    // TODO: Send verification email
    const url = `${process.env.NEXTAUTH_URL}/auth/register/verification?token=${verificationToken.token}`;
    console.log(url);
  }

  return {
    success: "Confirmtion email sent!",
  };
};

export const RegisterVerificationAction = async (values: RegisterFormData) => {
  const tZod = await getTranslations("zod");
  const validatedFields = RegisterVerificationSchema(tZod).safeParse(values);
  if (!validatedFields.success) return { error: "Invalid fields" };
  const { type, email, token, password, first_name, last_name } =
    validatedFields.data;
  const existingToken = await getVerificationTokenByToken({ token, type });
  if (!existingToken) {
    return { error: "Token does not exist" };
  }
  if (existingToken.identifier !== email) {
    return { error: "Invalid token" };
  }
  const hasExpired = new Date(existingToken.expires) < new Date();
  if (hasExpired) {
    return { error: "Token has expired" };
  }

  await prisma.user.create({
    data: {
      emailVerified: new Date(),
      email: existingToken.identifier,
      name: `${first_name} ${last_name}`,
      first_name: first_name ?? "",
      last_name: last_name ?? "",
      password: await bcrypt.hash(password, 10),
    },
  });

  await prisma.verificationToken.delete({
    where: { id: existingToken.id },
  });

  return { success: "Register user successfully" };
};

export const loginAction = async (values: LoginFormData) => {
  const tZod = await getTranslations("zod");
  const validatedFields = LoginSchema(tZod).safeParse(values);
  if (!validatedFields.success) return { error: "Invalid fields" };

  const { email, password } = validatedFields.data;

  const existingUser = await getUserByEmail(email);
  if (!existingUser || !existingUser.email || !existingUser.password) {
    return { error: "Email does not exist" };
  }

  if (!existingUser.emailVerified) {
    const verificationToken = await getVerificationTokenByEmail({
      email,
      type: VerificationTokenType.RegisterToken,
    });
    // TODO: Send verification email
    if (verificationToken) {
      // TODO: Send verification email
      const url = `${process.env.NEXTAUTH_URL}/auth/verification?token=${verificationToken.token}`;
      console.log(url);
    }
    return {
      success: "Confirmtion email sent!",
    };
  }

  try {
    await signIn("credentials", { email, password, redirect: false });
  } catch (error) {
    if (error instanceof AuthError) {
      switch (error.type) {
        case "CredentialsSignin":
          return { error: "Invalid credentials" };
        default:
          return { error: "Something went wrong" };
      }
    }
    throw error;
  }

  return {
    success: "Login successfully",
  };
};

export const forgotAction = async (values: ForgotFormData) => {
  const tZod = await getTranslations("zod");
  const validatedFields = ForgotSchema(tZod).safeParse(values);
  if (!validatedFields.success) return { error: "Invalid fields" };

  const { email } = validatedFields.data;

  const existingUser = await getUserByEmail(email);
  if (!existingUser || !existingUser.email) {
    return { error: "Email does not exist" };
  }

  const verificationToken = await generateVerificationToken({
    email: values.email,
    type: VerificationTokenType.ForgotToken,
  });

  if (!verificationToken) {
    return { error: "Failed to generate verification token" };
  }

  // TODO: Send verification email
  const url = `${process.env.NEXTAUTH_URL}/auth/forgot/verification?email=${email}&token=${verificationToken.token}`;
  console.log(url);
  return {
    success: "Send email successfully",
  };
};

export const forgotVerificationAction = async (
  values: ForgotVerificationFormData
) => {
  const tZod = await getTranslations("zod");
  const validatedFields = ForgotVerificationSchema(tZod).safeParse(values);
  if (!validatedFields.success) return { error: "Invalid fields" };

  const { email, token, password } = validatedFields.data;

  const verificationToken = await getVerificationTokenByToken({
    token,
    type: VerificationTokenType.ForgotToken,
  });
  if (!verificationToken) {
    return { error: "Invalid token" };
  }

  const hasExpired = new Date(verificationToken.expires) < new Date();
  if (hasExpired) {
    return { error: "Token has expired" };
  }

  if (verificationToken.identifier !== email) {
    return { error: "Invalid token" };
  }

  const user = await getUserByEmail(email);
  if (!user) {
    return { error: "User not found" };
  }
  let emailVerified = new Date();
  if (user.emailVerified) {
    emailVerified = user.emailVerified;
  }

  const updateUser = await prisma.user.update({
    where: { email: email },
    data: {
      password: await bcrypt.hash(password, 10),
      emailVerified: emailVerified,
    },
  });

  if (!updateUser) {
    return { error: "Invalid user" };
  }

  prisma.verificationToken.delete({
    where: {
      id: verificationToken.id,
    },
  });

  return {
    success: "Reset password successfully",
  };
};
